package com.wuliang.generate.common.core.filter;

import com.google.gson.Gson;
import com.wuliang.generate.common.core.utils.JsonUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * JWT令牌认证
 * <p>
 * 此处不嫩使用扫描注解，会发生启动时异常
 * @author WuLiang
 */
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    /**
     * 认证管理
     */
    private AuthenticationManager authenticationManager;

    /**
     * 对此过滤器进行初始化，声明过滤的接口地址
     *
     * @param authenticationManager 认证管理器
     */
    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
//        super.setFilterProcessesUrl("/auth/sendVerCode");
//        super.setFilterProcessesUrl("/auth/toRegistry");
    }

    /**
     * 是否还要继续其他认证方法
     *
     * @param request 请求
     * @param response 响应
     * @return 其他的认证方法
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws
                                                                                                          AuthenticationException {
        // 从输入流中获取到登录的信息
        try {
            Map<String, Object> requestBody = JsonUtils.jsonToMap(request.getInputStream());
            if (!requestBody.isEmpty()) {
                String userName = requestBody.get("userName").toString();
                String password = requestBody.get("password").toString();
                response.setHeader("Content-Type", "application/json");
                return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName, password));
            }
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 成功验证后调用的方法，如果验证成功，就生成token并返回
     *
     * @param request 请求
     * @param response 响应
     * @param chain 过滤器
     * @param authResult 认证结果
     * @throws IOException 读取请求异常
     * @throws ServletException 请求响应异常
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws
                                                                                                                                                    IOException,
                                                                                                                                                    ServletException {

        super.successfulAuthentication(request, response, chain, authResult);
    }

    /**
     * 这是验证失败时候调用的方法
     *
     * @param request 请求
     * @param response 响应
     * @param failed 认证失败时抛出的异常，也可以理解为为啥认证失败
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws
                                                                                                                                        IOException,
                                                                                                                                        ServletException {
        response.getWriter().write("authentication failed, reason: " + failed.getMessage());
    }
}
